/*
 * $Id: string_concat.c,v 1.3 2005-09-17 17:42:21 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/mstring.h>
#else
#include <xp/bas/string.h>
#endif

xp_size_t xp_strcat (xp_char_t* buf, const xp_char_t* str)
{
	xp_char_t* org = buf;	
	buf += xp_strlen(buf);
	while ((*buf++ = *str++) != XP_CHAR('\0'));
	return buf - org - 1;
}

xp_size_t xp_strcatn (xp_char_t* buf, const xp_char_t* str, xp_size_t n)
{
	xp_size_t x;
	xp_char_t* org = buf;
	const xp_char_t* end = str + n;

	x = xp_strlen(buf); buf += x;
	while (str < end) {
		if ((*buf++ = *str++) == XP_CHAR('\0')) return buf - org - 1;
	}
	return n + x;
}

xp_size_t xp_strncat (xp_char_t* buf, const xp_char_t* str, xp_size_t len)
{
	xp_size_t x;
	const xp_char_t* end = str + len;

	x = xp_strlen(buf); buf += x;
	while (str < end) *buf++ = *str++;
	*buf = XP_CHAR('\0');
	return len + x;
}

xp_size_t xp_strxcat (xp_char_t* buf, xp_size_t bsz, const xp_char_t* str)
{
	xp_char_t* p, * p2;
	xp_size_t blen;

	blen = xp_strlen(buf);
	if (blen >= bsz) return blen; /* something wrong */

	p = buf + blen;
	p2 = buf + bsz - 1;

	while (p < p2) {
		if (*str == XP_CHAR('\0')) break;
		*p++ = *str++;
	}

	if (bsz > 0) *p = XP_CHAR('\0');
	return p - buf;
}

xp_size_t xp_strxncat (
	xp_char_t* buf, xp_size_t bsz, const xp_char_t* str, xp_size_t len)
{
	xp_char_t* p, * p2;
	const xp_char_t* end;
	xp_size_t blen;

	blen = xp_strlen(buf);
	if (blen >= bsz) return blen; /* something wrong */

	p = buf + blen;
	p2 = buf + bsz - 1;

	end = str + len;

	while (p < p2) {
		if (str >= end) break;
		*p++ = *str++;
	}

	if (bsz > 0) *p = XP_CHAR('\0');
	return p - buf;
}

xp_size_t xp_strxapp (xp_char_t* buf, xp_size_t size, ...)
{
	xp_va_list ap;
	xp_size_t n;

	xp_va_start (ap, size);
	n = xp_strxappv (buf, size, ap);
	xp_va_end (ap);

	return n;
}

xp_size_t xp_strxappv (xp_char_t* buf, xp_size_t size, xp_va_list ap)
{
	const xp_char_t* p;
	xp_char_t* ptr = buf;
	xp_size_t left = size, n;

	while (left > 0) {
		p = xp_va_arg (ap, const xp_char_t*);
		if (p == XP_NULL) break;

		n = xp_strxcpy (ptr, left, p);
		left -= n; ptr += n;
	}

	return size - left;
}

/* strxcat + strxapp */
xp_size_t xp_strxcap (xp_char_t* buf, xp_size_t size, ...)
{
	xp_va_list ap;
	xp_size_t n;

	xp_va_start (ap, size);
	n = xp_strxcapv (buf, size, ap);
	xp_va_end (ap);

	return n;
}

xp_size_t xp_strxcapv (xp_char_t* buf, xp_size_t size, xp_va_list ap)
{
	const xp_char_t* p;
	xp_char_t* ptr;
	xp_size_t left, blen, n;

	blen = xp_strlen(buf);
	if (blen >= size) return blen; /* something wrong */

	left = size - blen; ptr = buf + blen;
	while (left > 0 && (p = xp_va_arg (ap, const xp_char_t*)) != XP_NULL) {
		n = xp_strxcpy (ptr, left, p);
		left -= n; ptr += n;
	}

	return size - left;
}

